package net.wwang.open.service;

import net.wwang.open.pojo.dto.UploadFileDTO;
import fr.opensagres.poi.xwpf.converter.xhtml.Base64EmbedImgManager;
import fr.opensagres.poi.xwpf.converter.xhtml.XHTMLConverter;
import fr.opensagres.poi.xwpf.converter.xhtml.XHTMLOptions;
import fr.opensagres.xdocreport.core.io.internal.ByteArrayOutputStream;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.poi.hwpf.HWPFDocumentCore;
import org.apache.poi.hwpf.converter.WordToHtmlConverter;
import org.apache.poi.hwpf.converter.WordToHtmlUtils;
import org.apache.poi.hwpf.usermodel.Picture;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.Base64;

/**
 * @author WangWei
 * @date 2020/8/11
 */
@Service
@Slf4j
public class FileService {
	private final Path fileStorageLocation;

	@Autowired
	public FileService(UploadFileDTO uploadFileDTO) {
		this.fileStorageLocation = Paths.get(uploadFileDTO.getUploadDir()).toAbsolutePath().normalize();
		try {
			Files.createDirectories(this.fileStorageLocation);
		} catch (Exception ex) {
			log.error(ex.toString());
		}
	}

	@Autowired
	FileService fileService;

	/**
	 * 存储文件
	 *
	 * @param file
	 * @return
	 */
	public UploadFileDTO storeFile(MultipartFile file) {
		// 规范化文件名
		String fileName = StringUtils.cleanPath(file.getOriginalFilename());
		UploadFileDTO properties = null;
		// 文件存储位置
		Path fileStorageLocation = this.fileStorageLocation;
		try {
			// 检查文件名是否包含无效字符
			if (fileName.contains("..")) {
				log.error("Sorry! Filename contains invalid path sequence " + fileName);
			}
			log.info(fileStorageLocation + fileName);
			// 将文件复制到目标位置（替换具有相同名称的现有文件）
			InputStream input = file.getInputStream();
			Path targetLocation = fileStorageLocation.resolve(fileName);
			Files.copy(input, targetLocation, StandardCopyOption.REPLACE_EXISTING);
			Path path = Paths.get(String.valueOf(fileStorageLocation), fileName);
			properties = new UploadFileDTO(fileStorageLocation.toString(), String.valueOf(path), fileName);
			return properties;
		} catch (IOException ex) {
			log.error("File copy exception：" + ex.toString());
		}
		return properties;
	}

    /**
     *  docx转Html
     * @param properties
     * @return
     */
	public static String docxToHtml(UploadFileDTO properties) {
		String htmlStr = "";
		try {
			FileInputStream fileInputStream = new FileInputStream(properties.getFileDir());
			XWPFDocument docxDocument = new XWPFDocument(fileInputStream);
			XHTMLOptions options = XHTMLOptions.create();
			//图片转base64
			options.setImageManager(new Base64EmbedImgManager());
			// 转换html
			ByteArrayOutputStream htmlStream = new ByteArrayOutputStream();
			XHTMLConverter.getInstance().convert(docxDocument, htmlStream, options);
			htmlStr = htmlStream.toString();
			htmlStream.close();
			fileInputStream.close();
		} catch (IOException e) {
			e.printStackTrace();
			log.error("File conversion abnormal, please check！");
		}
		return htmlStr;

	}

    /**
     * doc转html
     * @param properties
     * @return
     * @throws IOException
     * @throws ParserConfigurationException
     * @throws TransformerException
     */
	public String docToHtml(UploadFileDTO properties){
        String htmlStr = "";
        try {
            HWPFDocumentCore wordDocument = WordToHtmlUtils.loadDoc(new FileInputStream(properties.getFileDir()));
            WordToHtmlConverter wordToHtmlConverter = new ImageConverter(
                    DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument()
            );
            wordToHtmlConverter.processDocument(wordDocument);
            Document htmlDocument = wordToHtmlConverter.getDocument();
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            DOMSource domSource = new DOMSource(htmlDocument);
            StreamResult streamResult = new StreamResult(out);
            TransformerFactory transformerFactory = TransformerFactory.newInstance();
            Transformer serializer = transformerFactory.newTransformer();
            serializer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
            serializer.setOutputProperty(OutputKeys.INDENT, "yes");
            serializer.setOutputProperty(OutputKeys.METHOD, "html");
            serializer.transform(domSource, streamResult);
            out.close();
            htmlStr = new String(out.toByteArray());
        }catch (Exception e){
            e.printStackTrace();
            log.error("File conversion abnormal, please check!");
        }
		return htmlStr;
	}


    /**
     * 读取上传文件生成文档
     * @param file
     * @return
     */
	public net.wwang.open.pojo.Document generateDocument(MultipartFile file) {
	    //存储文件，返回文件传输实体
		UploadFileDTO properties = fileService.storeFile(file);
		//创建文档
		net.wwang.open.pojo.Document document = new net.wwang.open.pojo.Document();
		String title = "";
		String content = "";
		//原始文件名（包含后缀）
		String originName = properties.getFileName();
		try {
			if (originName.endsWith(".doc")) {
				title = originName.substring(0, originName.indexOf(".doc"));
				content = fileService.docToHtml(properties);
				//删除上传的文档
				FileUtils.forceDelete(Paths.get(properties.getUploadDir(), originName).toFile());
			} else {
				title = originName.substring(0, originName.indexOf(".docx"));
				content = docxToHtml(properties);
				FileUtils.forceDelete(Paths.get(properties.getUploadDir(), originName).toFile());
			}
		} catch (Exception e) {
			e.printStackTrace();
			log.error("Document generation failed, please check and try again!");
		}
		document.setTitle(title);
		document.setContent(content);
		return document;
	}

    /**
     * doc文件转html图片处理工具
     */
	class ImageConverter extends WordToHtmlConverter {
		public ImageConverter(Document document) {
			super(document);
		}

		@Override
		protected void processImageWithoutPicturesManager(Element currentBlock, boolean inlined, Picture picture) {
			Element imgNode = currentBlock.getOwnerDocument().createElement("img");
			StringBuffer sb = new StringBuffer();
			sb.append(Base64.getMimeEncoder().encodeToString(picture.getRawContent()));
			sb.insert(0, "data:" + picture.getMimeType() + ";base64,");
			imgNode.setAttribute("src", sb.toString());
			currentBlock.appendChild(imgNode);
		}
	}


}
